﻿using System;
using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Comm100.Framework.Exceptions;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Comm100.Framework.Authentication
{
    public class AspNetSessionAuthenticationHandler : AuthenticationHandler<AspNetSessionAuthenticationOptions>
    {
        public AspNetSessionAuthenticationHandler(
            IOptionsMonitor<AspNetSessionAuthenticationOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder,
            ISystemClock clock)
            : base(options, logger, encoder, clock)
        {
        }

        protected override Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            var sessionKey = Options.SessionKey;
            int siteId = 0;
            if (Options.IsSupportTenancy)
            {
                var qSiteId = this.Request.Query[Options.TenancyKey].ToString();
                if (string.IsNullOrEmpty(qSiteId))
                {
                    throw new MissingParameterException(Options.TenancyKey);
                } else
                {
                    try
                    {
                        siteId = int.Parse(qSiteId);
                        sessionKey = $"{Options.SessionKey}_{siteId}";
                    }
                    catch
                    {
                        throw new InvalidParameterException(Options.TenancyKey, qSiteId, "integer");
                    }
                }
            }

            var agentId = this.Context.Session.GetString(sessionKey);

            if (string.IsNullOrEmpty(agentId))
            {
                throw new AuthenticationFailedException();
            }

            var claims = new[] {
                new Claim(ClaimTypes.Role, Role.AGENT.ToString()),
                new Claim(ClaimTypes.NameIdentifier, agentId),
                new Claim(ClaimTypes.Name, "Allon"),    // TODO read name from db
                new Claim(Comm100ClaimTypes.SITE_ID, siteId.ToString()),
                new Claim(Comm100ClaimTypes.APPLICATION, "portal"),
            };
            var identity = new ClaimsIdentity(claims, "Session");
            var principal = new ClaimsPrincipal(identity);
            var ticket = new AuthenticationTicket(principal, "Session");
            return Task.FromResult(AuthenticateResult.Success(ticket));
        }
    }
}
